#ifndef __SPEED_LIMIT_H__
#define __SPEED_LIMIT_H__

#include <set>
#include "common.h"
#include "timer.h"

class TokenBucketCfg
{
public:
	//rate_limit: Bytes/sec
	//rate_burst: Bytes/sec
	//ms_per_tick: million seconds per tick
	TokenBucketCfg(uint32 rate_limit=UINT_MAX, uint32 rate_burst=UINT_MAX, uint32 ms_per_tick=1);
	void Init(uint32 rate_limit=UINT_MAX, uint32 rate_burst=UINT_MAX, uint32 ms_per_tick=1);

	uint32 rate_limit_;//rate limit per tick
	uint32 rate_burst_;//burst rate per tick
	uint32 ms_per_tick_;
};

class TokenBucket;

class ITokenBucketListner
{
public:
	virtual void OnTokenFilled(TokenBucket * pBucket) = 0;
	virtual void OnTokenEmpty(TokenBucket * pBucket) = 0;
};


class TokenBucket: public INTDTimerListener
{
public:
	TokenBucket();
	virtual ~TokenBucket();

	void Init(const TokenBucketCfg* cfg, bool reset=false, int32 lower_mark=0);
	int32 GetLimit();

	//if no tokens, need to suspend io events notification until next refilled
	//if no tokens, should start a refill timer at the same time
	int32 RemoveTokens(int32 bytes);

	//Refill tokens
	virtual void OnTimer(NTDTimer* pTimer);

	void AddListener(ITokenBucketListner * listener);
	void RemoveListener(ITokenBucketListner * listener);

private:
	uint32 GetTicks();
	bool Update();

private:
	int32 tokens_left_;
	int32 last_update_;
	int32 lower_mark_;
	TokenBucketCfg * cfg_;

	NTDTimer refill_timer_;

	std::set<ITokenBucketListner*> listener_set_;
};

//class SpdLimit
//{
//public:
//	SpdLimit();
//	~SpdLimit(){}
//
//	//Bytes per sec
//	void SetLimit(uint32 spdLimit, uint32 burstsize) { 
//		m_spdLimit = spdLimit; 
//		m_burstSize = burstsize;
//		m_msCircle = burstsize*1000/m_spdLimit;
//	}
//	void CancelLimit() { m_spdLimit = UINT_MAX; }
//	uint32 GetLeftBytes(uint32 exceptedBytes);
//
//private:
//	uint32 m_msCircle;
//	uint32 m_spdLimit;
//	uint32 m_leftBytes;
//	uint32 m_lastPeriod;
//	uint32 m_burstSize;
//};

#endif//__SPEED_LIMIT_H__